 1.特质之作为接口使用的特质
   
   Scala中的trait特质是一种特殊的概念。
   首先可以将trait作为接口来使用，此时的trait就与Java中的接口非常类似。
   在trait中可以定义抽象方法，与抽象类中的抽象方法一样，只要不给出方法的具体实现即可。
   类可以使用extends关键字继承trait。
   注意：在Scala中没有implement的概念，无论继承类还是trait特质，统一都是extends。
   类继承trait特质后，必须实现其中的抽象方法，实现时可以省略override关键字。
   Scala不支持对类进行多继承，但是支持多重继承trait特质，使用with关键字即可。

//定义一个trai特质
trait HelloTrait {
  def sayHello
}
//定义一个trai特质
trait MakeFriendTrait {
  def makeFriend
}
//继承多个trait,第一个trait使用extends关键字，其它trait使用with关键字
class Person(name: String) extends HelloTrait with MakeFriendsTrait with Serializable {
  override def sayHello() = println("Hello, My name is " + name)
  //override关键字也可以省略
  def makeFriend() = println("Hello，" + name)
}

object TraitDemo {
  def main(args: Array[String]): Unit = {
    val person = new Person("jacky")
    person.sayHello
    person.makFriend
  }

}
 2.带有具体实现的特质
   
   具体方法
   Scala中的trait特质不仅仅可以定义抽象方法，还可以定义具体实现的方法，这时的trait更像是包含了通
用工具方法的类。比如，trait中可以包含一些很多类都通用的功能方法，比如打印日志等等，Spark中就使用
了trait来定义通用的日志打印方法。
   具体字段
   Scala trait特质中的字段可以是抽象的，也可以是具体的。

trait People {
  //定义抽象字段
  val name: String
  //定义了age字段
  val age = 30
  
  def eat(message: String): Unit = {
    println(message)
  }
}

trait Worker {
  //这个trait也定义了age字段
  val age = 25

  def work: Unit = {
    println("Working......")
  }
}
// Student类继承了Worker、Person这两个特质，需要使用extends、with这两个关键字
class Student extends Woker with People {
  //重写name抽象字段，此处override可以省略
  override val name: String = "lisi"
  //由于Woker和People中都有age字段，所以当Student类继承这两个特质时
  //需要重写age字段，并且要使用override关键字，否则就会报错
  //此时的override关键字不能省略
  override val age = 20
}

object TraitDemoTwo {
  def main(args: Array[String]): Unit = {
    val stu = new Student
    stu.eat
    stu.work
    println(s"姓名：${stu.name}, 年龄：${stu.age}")
  }

}
   注意：特质Person和Worker中都有age字段，当Student继承这两个特质时，需要重写age字段，并且
要用override关键字，否则就会报错。

 3.特质构造顺序
   
   在Scala中，trait特质也是有构造器的，也就是trait中的不包含在任何方法中的代码。
   构造器以如下顺序执行：
   1)、执行父类的构造器；
   2)、执行trait的构造器，多个trait从左到右依次执行；
   3)、构造trait时会先构造父trait，如果多个trait继承同一个父trait，则父trait只会构造一次；
   4)、所有trait构造完毕之后，子类的构造器才执行
   
package lagou.cn.part06

class Person2{
  println("Person's Constructor!")
}

trait Logger{
  println("Logger's Constructor!")
}

trait MyLogger extends Logger{
  println("MyLogger's Constructor!")
}

trait TimeLogger extends Logger{
  println("TimeLogger's Constructor!")
}
//如果一个类继承了父类，也继承特质，那么要先写父类，再写特质
//extends 父类 with 特质1 with 特质2.....
class Student2 extends Person2 with MyLogger with TimeLogger {
  println("Student's Constructor!")
}

object TraitDemoThree {
  def main(args: Array[String]): Unit = {
    val stu = new Student2

  }

}


   上面代码的输出结果：
Person's constructor!
Logger's constructor!
MyLogger's constructor!
TimeLogger's constructor!
Student's constructor!
   
 4.特质继承类
   
   在Scala中，trait特质也可以继承class类，此时这个class类就会成为所有继承此trait的类的父类。

package lagou.cn.part06

class MyUtil {
  def printMessage(msg: String): Unit = {
    println(msg)
  }
}

trait Log extends MyUtil {
  def log(msg: String): Unit = {
    println(msg)
  }
}

//Person3类继承Log特质，Log特质继承MyUtil类，所以MyUtil类成为Person3的父类
class Person3(name: String) extends Log {
  def sayHello: Unit = {
    log("Hello, " + name)
    printMessage("hi, " + name)
  }
}

object TraitDenoFour {
  def main(args: Array[String]): Unit = {
    val person = new Person3("jacky")
    person.sayHello
  }
}


 5.Ordered和Ordering
   
   在Java中对象的比较有两个接口，分别是Comparable和Comparator。它们之间的区别在于：
   实现Comparable接口的类，重写compareTo()方法后，其对象自身就具有了可比较性；
   实现Comparator接口的类，重写了compare()方法后，则提供一个第三方比较器，用于比较两个对象。
   在Scala中也引入了以上两种比较方法(Scala.math包下):
   Ordered特质混入Java的Comparable接口，它定义了相同类型间的比较方式，但这种内部比较方式是
单一的；

trait Ordered[A] extends Any with java.lang.Comparable[A]{......}
   
   Ordering特质混入Comparator接口，它是提供第三方比较器，可以自定义多种比较方式，在实际开发
中也是使用比较多的，灵活解耦合。

trait Ordering[T] extends Comparator[T] with PartialOrdering[T] with
Serializable {......}
   
   使用Ordered特质进行排序操作
case class Project(tag:String, score:Int) extends Ordered[Project] {
     def compare(pro:Project ) = tag.compareTo(pro.tag)
}

object OrderedDemo {
  def main(args: Array[String]): Unit = {
    val list = List(Project("hadoop",60), Project("flink",90),
                    Project("hive",70),Project("spark",80))
    println(list.sorted)
  }
}

   使用Ordering特质进行排序操作

object OrderingDemo {
  def main(args: Array[String]): Unit = {
  val pairs = Array(("a", 7, 2), ("c", 9, 1), ("b", 8, 3))
  // Ordering.by[(Int,Int,Double),Int](_._2)表示从Tuple3转到Int型
  // 并按此Tuple3中第二个元素进行排序
  Sorting.quickSort(pairs)(Ordering.by[(String, Int, Int), Int](_._2))
  println(pairs.toBuffer)
  }
}